package com.naiterui.ehp.bs.patient.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.ehp.bp.domain.DrVisitRecord;
import com.naiterui.ehp.bp.domain.DrVisitTemplet;
import com.naiterui.ehp.bp.domain.Patient;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.exception.JsonException;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.biz.NameUtils;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.net.RestHttpUtil;
import com.naiterui.ehp.bs.patient.dao.IPatientDao;
import com.naiterui.ehp.bs.patient.exception.ExceptionCodes;
import com.naiterui.ehp.bs.patient.repository.IApPatientVisitRecordRepository;
import com.naiterui.ehp.bs.patient.repository.IApPatientVisitTempletRepository;
import com.naiterui.ehp.bs.patient.service.IPatientVisitService;
import com.naiterui.ehp.bs.patient.utils.ConfigKeyUtil;
import com.naiterui.ehp.bs.patient.utils.LimitValueConfig;
import com.naiterui.ehp.bs.patient.utils.exception.PatientBusinessException;
import com.naiterui.ehp.bs.patient.vo.visit.DrVisitRecomVO;
import com.naiterui.ehp.bs.patient.vo.visit.PatientVisitOptionVO;
import com.naiterui.ehp.bs.patient.vo.visit.PatientVisitQuestionVO;
import com.naiterui.ehp.bs.patient.vo.visit.PatientVisitRecordVO;
import com.naiterui.ehp.bs.patient.vo.visit.PatientVisitVO;

@Service
public class ApPatientVisitServiceImpl implements IPatientVisitService {
    private static final Logger LOGGER = LoggerFactory.getLogger(ApPatientVisitServiceImpl.class);

    private static final String DATE_FORMAT = "yyyy/MM/dd";

    @Autowired
    private IApPatientVisitRecordRepository patientVisitRecordRepository;

    @Autowired
    private IApPatientVisitTempletRepository patientVisitTempletRepository;

    @Autowired
    private IPatientDao patientDao;

    @Override
    public PatientVisitRecordVO getVisitDetailsById(Long patientId, Long visitId) throws BusinessException {
        DrVisitRecord record = this.patientVisitRecordRepository.get(visitId);
        if (record == null) {
            LOGGER.error("随访记录不存在！visitId:{}", visitId);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_RECORD_NOT_EXIST);
        }

        Long dbPatientId = record.getPatientId();
        if (!dbPatientId.equals(patientId)) {
            LOGGER.error("当前患者与随访记录患者信息不匹配！db-patientId:{}", dbPatientId);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_NOT_MATCH);
        }

        PatientVisitRecordVO recordVO = new PatientVisitRecordVO();
        recordVO.setVisitSerialNumber(record.getSerialNumber());
        String visitTime = DateUtil.formatDate(record.getCreatedAt(), DATE_FORMAT);
        recordVO.setVisitTime(visitTime);
        // 填写状态
        Integer status = record.getStatus();
        recordVO.setVisitStatus(status);

        /*
         * 拼装随访记录
         */
        List<PatientVisitQuestionVO> visitDetails = this.buildVisitRecord(record);
        recordVO.setVisitContent(visitDetails);

        // 自主购药
        Long orderId = record.getOrderId();
        recordVO.setOrderId(orderId);
        /*
         * 已屏蔽获取药品信息的入口
         */
        recordVO.setShowCount(PatientVisitRecordVO.SHOW_COUNT_NO);
        recordVO.setMedicationCount(0);

        /*
         * 查询患者相关个人信息
         */
        Patient patient = this.patientDao.get(patientId);
        if (patient == null) {
            LOGGER.error("---------- getVisitDetailsById() ERROR ; 随访记录，患者ID不存在,patientId={}", patientId);
            throw new BusinessException(ExceptionCodes.PATIENT_NOT_EXIST);
        }
        String name = patient.getName();
        recordVO.setPatientName(StringUtils.isNotBlank(name) ? name : patient.getNickName());
        recordVO.setPatientGender(patient.getGender());
        Integer age = patient.getAge();
        recordVO.setPatientAge(age == null ? "" : String.valueOf(age));

        return recordVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveVisitInfo(Long visitId, String visitInfo, Long patientId) throws PatientBusinessException {
        /*
         * 锁表查询随访记录是否存在
         */
        DrVisitRecord visitRecord = this.patientVisitRecordRepository.findFirstById(visitId);
        if (visitRecord == null) {
            LOGGER.error("随访记录不存在！visitId:{}", visitId);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_RECORD_NOT_EXIST);
        }

        Long dbPatientId = visitRecord.getPatientId();
        if (!dbPatientId.equals(patientId)) {
            LOGGER.error("当前患者与随访记录患者信息不匹配！db-patientId:{}", dbPatientId);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_NOT_MATCH);
        }

        if (DrVisitRecord.VISIT_STATUS_VISITED.equals(visitRecord.getStatus())) {
            LOGGER.info("患者已经提交过随访！");
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLED);
        }

        /*
         * 校验用户提交的回访格式
         */
        Map<String, String> map = this.checkPatientVisit(visitInfo, visitRecord.getTempletId());
        String visitDesc = map.get("visitDesc");
        if (StringUtils.isNotBlank(visitDesc) && visitDesc.length() >= 50) {
            visitDesc = visitDesc.substring(0, 50);
        }
        visitRecord.setVisitDesc(visitDesc);
        visitRecord.setVisitRecord(map.get("visitRecord"));
        visitRecord.setStatus(DrVisitRecord.VISIT_STATUS_VISITED);
        visitRecord.setChangedAt(new Date());
        this.patientVisitRecordRepository.update(visitRecord);

        /*
         *  2. 异步调用IM通知医生
         */
        String url = ConfigKeyUtil.getString(ConfigKeyUtil.PATIENT_VISIT_ANSWER_TO_DOCTOR);
        Map<String, String> params = new HashMap<>();
        params.put("doctorId", String.valueOf(visitRecord.getDoctorId()));
        params.put("patientId", String.valueOf(patientId));
        params.put("visitId", String.valueOf(visitId));
        params.put("viewMessage", visitDesc);
        params.put("orderId", String.valueOf(visitRecord.getOrderId()));
        // 发送通知
        LOGGER.info(" send visit info --- params = {}", params.toString());
        RestHttpUtil.post().url(url).paramMap(params).asyncExecuteData();
    }

    @Override
    @Deprecated
    public DrVisitRecomVO getVisitPrescriptionDetails(Long orderId, Long patientId) throws BusinessException {
        DrVisitRecomVO retRecomVO = new DrVisitRecomVO();
        retRecomVO.setRecomId(0L);
        retRecomVO.setSerialNumber("");
        retRecomVO.setRecomDate("");
        retRecomVO.setDiagnosis("");
        retRecomVO.setItems(new ArrayList<>());
        retRecomVO.setDoctorName("");
        retRecomVO.setPatientName("");
        retRecomVO.setPatientGender(Patient.GENDER_UNKNOWN);
        retRecomVO.setPatientAge("");
        retRecomVO.setPatientArea("");
        return retRecomVO;
    }

    /**
     * 拼装随访记录
     *
     * @param record 随访记录
     *
     * @return
     *
     * @throws PatientBusinessException
     * @History 2016年11月29日 下午5:34:25 by wangchuan
     */
    private List<PatientVisitQuestionVO> buildVisitRecord(DrVisitRecord record) throws PatientBusinessException {
        Long templetId = record.getTempletId();
        DrVisitTemplet templetInfo = this.patientVisitTempletRepository.get(templetId);
        if (templetInfo == null) {
            LOGGER.error("随访模板不存在【{}】", templetId);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_TEMPLET_NOT_EXIST);
        }
        String templet = templetInfo.getTemplet();
        /*
         * 模板中的问题和答案选项
         */
        List<PatientVisitQuestionVO> templetQAList;
        try {
            templetQAList = JsonMapper.toList(templet, PatientVisitQuestionVO.class);
        } catch (Exception e) {
            LOGGER.error("随访模板问题设置为空！", e);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_TEMPLET_QUESTION_NOT_EXIST, e);
        }

        // 1. 还未填写
        if (DrVisitRecord.VISIT_STATUS_UNVISIT.equals(record.getStatus())) {
            return templetQAList;
        }

        /*
         *  2. 已经填写，解析患者回答
         */
        // 患者回答内容
        String content = record.getVisitRecord();
        List<PatientVisitVO> visitRecordList;
        try {
            visitRecordList = JsonMapper.toList(content, PatientVisitVO.class);
        } catch (Exception e) {
            LOGGER.error("患者用药随访填写有误！visitId:{};doctorId:{};patientId:{}", record.getId(), record.getDoctorId(), record.getPatientId(), e);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLING_WRONG, e);
        }

        // 患者回答放进map中
        Map<Integer, PatientVisitVO> userAnswerMap = new HashMap<>();
        for (PatientVisitVO patientVisit : visitRecordList) {
            userAnswerMap.put(patientVisit.getQuestionIndex(), patientVisit);
        }

        /*
         *  将患者的回答放进随访模板中，作为最终的显示
         */
        for (PatientVisitQuestionVO visitQAListVO : templetQAList) {
            Integer questionIndex = visitQAListVO.getQuestionIndex();
            // 此问题，患者没有回答
            if (!userAnswerMap.containsKey(questionIndex)) {
                continue;
            }

            // 患者回答
            PatientVisitVO patientVisitVO = userAnswerMap.get(questionIndex);
            // --多选的处理
            if (DrVisitTemplet.ANSWER_TYPE_CHECKBOX.equals(visitQAListVO.getAnswerType())) {
                // 患者的选择答案
                List<Integer> selectedList = Arrays.asList(patientVisitVO.getSelection());
                if (selectedList.isEmpty()) {
                    continue;
                }

                List<PatientVisitOptionVO> options = visitQAListVO.getOptions();
                for (PatientVisitOptionVO option : options) {
                    Integer optionIndex = option.getOptionIndex();
                    // 选中了某个项
                    if (selectedList.contains(optionIndex)) {
                        option.setSelected(PatientVisitOptionVO.OPTION_SELECT_STATUS_SELECTED);
                    }
                }
            }
            // --填空的处理
            else {
                visitQAListVO.setAnswer(patientVisitVO.getAnswer());
            }
        }
        return templetQAList;
    }

    /**
     * 校验患者回访记录
     *
     * @param visitInfo 患者提交
     * @param templetId 模板id
     *
     * @return
     *
     * @throws PatientBusinessException
     * @History 2016年11月29日 下午5:52:07 by wangchuan
     */
    private Map<String, String> checkPatientVisit(String visitInfo, Long templetId) throws PatientBusinessException {
        /*
         * 患者回答转list
         */
        List<PatientVisitVO> visitList;
        if (visitInfo.startsWith("[") && visitInfo.endsWith("]") && visitInfo.length() > 2) {
            try {
                visitList = JsonMapper.toList(visitInfo, PatientVisitVO.class);
            } catch (Exception e) {
                LOGGER.error("填写随访记录异常！visitInfo:{}", visitInfo, e);
                throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLING_WRONG, e);
            }
        } else {
            throw new PatientBusinessException(ExceptionCodes.PARAM_ERROR);
        }
        if (visitList == null || visitList.size() <= 0) {
            LOGGER.error("患者未回答任何问题");
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLING_EMPTY);
        }

        DrVisitTemplet templetInfo = this.patientVisitTempletRepository.get(templetId);
        String templet = templetInfo.getTemplet();
        // 模板
        List<PatientVisitQuestionVO> templetQAList;
        try {
            templetQAList = JsonMapper.toList(templet, PatientVisitQuestionVO.class);
        } catch (Exception e) {
            LOGGER.error("随访模板问题设置为空！", e);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_TEMPLET_QUESTION_NOT_EXIST, e);
        }

        // 模板中所有问题序号
        Set<Integer> questionIndexes = new HashSet<>();
        for (PatientVisitQuestionVO visitQuestionVO : templetQAList) {
            questionIndexes.add(visitQuestionVO.getQuestionIndex());
        }

        // 患者回答放进map中
        Map<Integer, PatientVisitVO> userAnswerMap = new HashMap<>();
        Iterator<PatientVisitVO> iterator = visitList.iterator();
        while (iterator.hasNext()) {
            PatientVisitVO patientVisit = iterator.next();
            Integer questionIndex = patientVisit.getQuestionIndex();
            if (!questionIndexes.contains(questionIndex)) {
                LOGGER.error("患者回答与模板设置问题不对应");
                throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLING_WRONG);
            }

            if (DrVisitTemplet.ANSWER_TYPE_CHECKBOX.equals(patientVisit.getAnswerType())) {
                // 患者勾选
                Integer[] selection = patientVisit.getSelection();
                if (selection == null || selection.length <= 0) {
                    iterator.remove();
                    continue;
                }

                // 对患者勾选去重
                Set<Integer> selectedSet = new HashSet<>(Arrays.asList(selection));
                Integer[] selectedOptions = selectedSet.toArray(new Integer[selectedSet.size()]);
                patientVisit.setSelection(selectedOptions);
            } else {
                String answer = patientVisit.getAnswer();
                if (StringUtils.isBlank(answer)) {
                    iterator.remove();
                    continue;
                }

                // 替换emoji表情
                // answer = NameUtils.handleUtf8mb4(answer, "");

                // 内容统一校验长度(300,0)，文本校验规则
                if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_VISIT_ANSWER, answer)) {
                    LOGGER.error("患者提交用药随访，回答字符长度超过限制！！answer:{}", answer);
                    throw new PatientBusinessException(ExceptionCodes.DR_VISIT_INVALID_CONTENT_LENGTH);
                }

                if (!answer.trim().matches(NameUtils.VALIDATE_REGEX_OTHERS)) {
                    LOGGER.error("患者提交用药随访，回答中包含有特殊字符！！answer:{}", answer);
                    throw new PatientBusinessException(ExceptionCodes.EMOJI_ERROR);
                }
            }

            userAnswerMap.put(questionIndex, patientVisit);
        }

        if (userAnswerMap.isEmpty()) {
            LOGGER.error("患者未回答任何问题");
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLING_EMPTY);
        }

        // 将问题和用户回答拼接成一个描述信息存储
        StringBuilder sb = new StringBuilder();
        for (PatientVisitQuestionVO visitQAListVO : templetQAList) {
            // 问题序号
            Integer questionIndex = visitQAListVO.getQuestionIndex();
            int index = questionIndex + 1;
            sb.append(index).append(".");
            sb.append(visitQAListVO.getQuestion());

            // 患者未回答该问题
            if (!userAnswerMap.containsKey(questionIndex)) {
                sb.append("\n");
                continue;
            }

            PatientVisitVO patientVisitVO = userAnswerMap.get(questionIndex);
            // -多选题
            if (DrVisitTemplet.ANSWER_TYPE_CHECKBOX.equals(visitQAListVO.getAnswerType())) {
                // 患者勾选
                Integer[] selection = patientVisitVO.getSelection();
                if (selection == null || selection.length <= 0) {
                    continue;
                }

                // 模板选项
                List<PatientVisitOptionVO> options = visitQAListVO.getOptions();

                // 模板中选项序号
                Set<Integer> optionIndexes = new HashSet<>();
                // 患者勾选的选项序号
                Set<Integer> selectedIndexes = new HashSet<>(Arrays.asList(selection));
                for (PatientVisitOptionVO visitOption : options) {
                    Integer optionIndex = visitOption.getOptionIndex();
                    optionIndexes.add(optionIndex);

                    // 选中了某个项
                    if (selectedIndexes.contains(optionIndex)) {
                        sb.append(visitOption.getOption()).append(" ");
                    }
                }

                // 模板中没有该勾选选项
                if (!optionIndexes.containsAll(selectedIndexes)) {
                    LOGGER.error("患者勾选的选项与模板中不一致！");
                    throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLING_WRONG);
                }
            }
            // -填空题
            else {
                String answer = patientVisitVO.getAnswer();
                if (StringUtils.isNotBlank(answer)) {
                    sb.append(answer);
                }
            }
            sb.append("\n");
        }

        String visitInfoSave;
        try {
            visitInfoSave = JsonMapper.toJson(visitList);
        } catch (JsonException e) {
            LOGGER.error("患者回答格式有误！", e);
            throw new PatientBusinessException(ExceptionCodes.DR_VISIT_PATIENT_FILLING_WRONG, e);
        }

        Map<String, String> retMap = new HashMap<>();
        retMap.put("visitRecord", visitInfoSave);

        String visitDesc = sb.toString();
        // 去掉最后加的换行符
        // visitDesc = visitDesc.length() > 2 ? visitDesc.substring(0, visitDesc.length() - 2) :
        // visitDesc;
        retMap.put("visitDesc", visitDesc);
        return retMap;
    }
}
